# frozen_string_literal: true

module Resolvers
  class VulnerabilitySeveritiesCountResolver < VulnerabilitiesBaseResolver
    include Gitlab::Utils::StrongMemoize
    include Gitlab::Graphql::Authorize::AuthorizeResource

    type Types::VulnerabilitySeveritiesCountType, null: true
    authorize :read_security_resource
    authorizes_object!

    argument :project_id, [GraphQL::Types::ID],
             required: false,
             description: 'Filter vulnerabilities by project.'

    argument :report_type, [Types::VulnerabilityReportTypeEnum],
             required: false,
             description: 'Filter vulnerabilities by report type.'

    argument :severity, [Types::VulnerabilitySeverityEnum],
             required: false,
             description: 'Filter vulnerabilities by severity.'

    argument :state, [Types::VulnerabilityStateEnum],
             required: false,
             description: 'Filter vulnerabilities by state.'

    argument :scanner, [GraphQL::Types::String],
             required: false,
             description: 'Filter vulnerabilities by scanner.'

    argument :scanner_id, [::Types::GlobalIDType[::Vulnerabilities::Scanner]],
             required: false,
             description: 'Filter vulnerabilities by scanner ID.'

    argument :has_issues, GraphQL::Types::Boolean,
             required: false,
             description: 'Filter vulnerabilities that do or do not have issues.'

    argument :has_resolution, GraphQL::Types::Boolean,
             required: false,
             description: 'Filter vulnerabilities that do or do not have a resolution.'

    argument :image, [GraphQL::Types::String],
             required: false,
             description: "Filter vulnerabilities by location image. When this filter is present, "\
                          "the response only matches entries for a `reportType` "\
                          "that includes #{::Vulnerabilities::Finding::REPORT_TYPES_WITH_LOCATION_IMAGE.map { |type| "`#{type}`" }.join(', ')}."

    argument :cluster_agent_id, [::Types::GlobalIDType[::Clusters::Agent]],
             prepare: ->(ids, _) { ids.map(&:model_id) },
             required: false,
             description: "Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` "\
                          "of `cluster_image_scanning` are only included with this filter."

    def resolve(**args)
      return Vulnerability.none unless vulnerable

      args[:scanner_id] = resolve_gids(args[:scanner_id], ::Vulnerabilities::Scanner) if args[:scanner_id]

      Hash.new(0)
        .merge(vulnerabilities(args).grouped_by_severity.count)
    end

    private

    def vulnerabilities(filters)
      finder = if !vulnerable.is_a?(::InstanceSecurityDashboard)
                 Security::VulnerabilityReadsFinder
               else
                 Security::VulnerabilitiesFinder
               end

      finder.new(vulnerable, filters).execute
    end
  end
end
